package org.jheuristics.util;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;


/**
 * TODO
 *
 * @author Marcell Manfrin, marcell at ourgrid.org, 2005
 */
public class DecisionGenEnum implements GenEnum {
	private GenEnum decision;
	private GenEnum[] gens;

	/**
	 * TODO
	 *
	 * @param maximums
	 */
	public DecisionGenEnum(int[] maximums) {
		if (null == maximums) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		if (0 == maximums.length) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}
		decision = new SimpleGenEnum(maximums.length, true);
		gens = new GenEnum[maximums.length];
		for (int i = 0; i < gens.length; i++) {
			gens[i] = new SimpleGenEnum(maximums[i], false);
		}
	}

	/**
	 * TODO
	 *
	 * @param maximums
	 * @param random
	 */
	public DecisionGenEnum(int[] maximums, RandomGenerator random) {
		if (null == maximums) {
			// TODO: ERROR MSG
			throw new NullPointerException();
		}
		if (0 == maximums.length) {
			// TODO: ERROR MSG
			throw new IllegalArgumentException();
		}
		decision = new SimpleGenEnum(maximums.length-1, true, random);
		gens = new GenEnum[maximums.length];
		for (int i = 0; i < gens.length; i++) {
			gens[i] = new SimpleGenEnum(maximums[i], false, random);
		}
	}

	/**
	 * TODO
	 *
	 * @param decision
	 * @param gens
	 */
	private DecisionGenEnum(GenEnum decision, GenEnum[] gens) {
		this.decision = decision;
		this.gens = gens;
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#up()
	 */
	public GenEnum up() {
		GenEnum newDecision = decision;
		GenEnum[] newGens;
		int group = decision.getValue();
		if (!gens[group].canUp()) {
			newDecision = decision.up();
		}
		newGens = new GenEnum[gens.length];
		for (int i = 0; i < gens.length; i++) {
			newGens[i] = gens[i].up();
		}
		return new DecisionGenEnum(newDecision, newGens);
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#down()
	 */
	public GenEnum down() {
		GenEnum newDecision = decision;
		GenEnum[] newGens;
		int group = decision.getValue();
		if (!gens[group].canDown()) {
			newDecision = decision.up();
		}
		newGens = new GenEnum[gens.length];
		for (int i = 0; i < gens.length; i++) {
			newGens[i] = gens[i].down();
		}
		return new DecisionGenEnum(newDecision, newGens);
	}

	/**
	 * TODO
	 *
	 * @param random
	 * @return
	 * @see org.jheuristics.util.GenEnum#random(org.jheuristics.util.RandomGenerator)
	 */
	public GenEnum random(RandomGenerator random) {
		GenEnum newDecision = new SimpleGenEnum(gens.length-1, true, random);
		GenEnum[] newGens = new GenEnum[gens.length];
		for (int i = 0; i < newGens.length; i++) {
			newGens[i] = gens[i].random(random);
		}
		return new DecisionGenEnum(newDecision, newGens);
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#canUp()
	 */
	public boolean canUp() {
		return gens.length > 1 || gens[0].canUp();
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#canDown()
	 */
	public boolean canDown() {
		return gens.length > 1 || gens[0].canDown();
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#getValue()
	 */
	public int getValue() {
		return decision.getValue();
	}

	/**
	 * TODO
	 *
	 * @return
	 */
	public int getDecisionValue() {
		return gens[decision.getValue()].getValue();
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see org.jheuristics.util.GenEnum#getMaximum()
	 */
	public int getMaximum() {
		return decision.getMaximum();
	}

	/**
	 * TODO
	 *
	 * @param obj
	 * @return
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object obj) {
		if (!(obj instanceof DecisionGenEnum)) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		DecisionGenEnum gen = (DecisionGenEnum) obj;
		return new EqualsBuilder().appendSuper(super.equals(obj)).append(decision, gen.decision).append(gens, gen.gens).isEquals();
	}

	/**
	 * TODO
	 *
	 * @return
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return new HashCodeBuilder(19, 35).append(decision).append(gens).toHashCode();
	}


	/**
	 * TODO
	 *
	 * @return
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer str = new StringBuffer("{");
		for (int i = 0; i < gens.length; i++) {
			if (decision.getValue() == i) {
				str.append("[");
				str.append(gens[i].getValue());
				str.append("]");
			} else {
				str.append(gens[i].getValue());
			}
			if (gens.length != i+1) {
				str.append(", ");
			}
		}
		str.append("}");
		return str.toString();
	}

}
